package com.ygl.consumer.lb;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.ribbon.ExtendBalancer;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Author yanggld
 * @Date 2019/11/21-18:40
 * @Description
 * 实现同一集群优先调用并基于随机权重的负载均衡策略
 *
 */
@Slf4j
public class NacosSameClusterWeightRule extends AbstractLoadBalancerRule {

	@Autowired
	private NacosDiscoveryProperties discoveryProperties;


	@Override
	public void initWithNiwsConfig(IClientConfig clientConfig) {
	}

	@Override
	public Server choose(Object key) {
		BaseLoadBalancer lb = (BaseLoadBalancer)getLoadBalancer();
		String clientName = lb.getName();
		// 获取配置文件中所配置的集群名称
		String clusterName = discoveryProperties.getClusterName();
		// 获取服务发现的相关API
		NamingService namingService = discoveryProperties.namingServiceInstance();
		try {
			// 获取该微服务的所有健康实例
			List<Instance> instances = namingService.selectInstances(clientName, true);
			// 过滤出相同集群下的所有实例
			List<Instance> sameClusterInstances = instances.stream()
					.filter(i -> Objects.equals(i.getClusterName(), clusterName))
					.collect(Collectors.toList());

			// 相同集群下没有实例则需要使用其他集群下的实例
			List<Instance> instancesToBeChosen;
			if (CollectionUtils.isEmpty(sameClusterInstances)) {
				instancesToBeChosen = instances;
				log.warn("发生跨集群调用，name = {}, clusterName = {}, instances = {}",
						clientName, clusterName, instances);
			} else {
				instancesToBeChosen = sameClusterInstances;
			}

			// 基于随机权重的负载均衡算法，从实例列表中选取一个实例
			Instance instance = ExtendBalancer.getHostByRandomWeight2(instancesToBeChosen);
			log.info("选择的实例是：port = {}, instance = {}", instance.getPort(), instance);

			return new NacosServer(instance);
		} catch (NacosException e) {
			log.error("获取实例发生异常", e);
			return null;
		}
	}
}
